package com.ejustcn.js;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;

import javax.servlet.http.HttpServletResponse;

import com.vaadin.server.Constants;
import com.vaadin.server.DownloadStream;
import com.vaadin.server.FileResource;
import com.vaadin.server.RequestHandler;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
import com.vaadin.shared.ApplicationConstants;


public class StaticJsFileHandler implements RequestHandler {

	@Override
	public boolean handleRequest(VaadinSession session, VaadinRequest request,
			VaadinResponse response) throws IOException {
		if ( !hasPathPrefix(request, ApplicationConstants.PUBLISHED_FILE_PATH
                + "/VAADIN/static/")){
			return false;
		}
		
		String pathInfo = request.getPathInfo();
		String fileName = pathInfo
                .substring(ApplicationConstants.PUBLISHED_FILE_PATH.length() + 2);
     // Find the application directory
        String basepath = VaadinService.getCurrent()
                          .getBaseDirectory().getAbsolutePath();

        // Image as a file resource
        FileResource resource = new FileResource(new File(basepath +"/"+ fileName));

        writeResponse(response,resource.getStream());
        
        return true;
	}
	
	
	private static boolean hasPathPrefix(VaadinRequest request, String prefix) {
        String pathInfo = request.getPathInfo();

        if (pathInfo == null) {
            return false;
        }

        if (!prefix.startsWith("/")) {
            prefix = '/' + prefix;
        }

        if (pathInfo.startsWith(prefix)) {
            return true;
        }

        return false;
    }

	/**
	 * copy and modified from {@link com.vaadin.server.DownloadStream#writeResponse}
	 * @param data
	 * @throws IOException
	 */
	private void writeResponse(VaadinResponse response,DownloadStream ds)
            throws IOException {
        // Download from given stream
		InputStream data=ds.getStream();
        if (data == null) {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        if (data != null) {

            OutputStream out = null;
            try {
                // Sets content type
            	response.setContentType("text/javascript");
                // Sets cache headers
                response.setCacheTime(ds.getCacheTime());

                // Copy download stream parameters directly
                // to HTTP headers.
                final Iterator<String> i = ds.getParameterNames();
                if (i != null) {
                    while (i.hasNext()) {
                        final String param = i.next();
                        response.setHeader(param, ds.getParameter(param));
                    }
                }

                int bufferSize = ds.getBufferSize();
                if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) {
                    bufferSize = Constants.DEFAULT_BUFFER_SIZE;
                }
                final byte[] buffer = new byte[bufferSize];
                int bytesRead = 0;

                out = response.getOutputStream();

                long totalWritten = 0;
                while ((bytesRead = data.read(buffer)) > 0) {
                    out.write(buffer, 0, bytesRead);

                    totalWritten += bytesRead;
                    if (totalWritten >= buffer.length) {
                        // Avoid chunked encoding for small resources
                        out.flush();
                    }
                }
            } finally {
            	tryToCloseStream(out);
            	tryToCloseStream(data);
            }
        }
    }
	
	
	static void tryToCloseStream(OutputStream out) {
        try {
            // try to close output stream (e.g. file handle)
            if (out != null) {
                out.close();
            }
        } catch (IOException e1) {
            // NOP
        }
	}
	
	static void tryToCloseStream(InputStream in) {
        try {
            // try to close output stream (e.g. file handle)
            if (in != null) {
                in.close();
            }
        } catch (IOException e1) {
            // NOP
        }
    }
	
	
}
